/**
 * Software License, Version 1.0 Copyright 2003 The Trustees of Indiana
 * University. All rights reserved. Redistribution and use in source and binary
 * forms, with or without modification, are permitted provided that the
 * following conditions are met: 1) All redistributions of source code must
 * retain the above copyright notice, the list of authors in the original source
 * code, this list of conditions and the disclaimer listed in this license; 2)
 * All redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the disclaimer listed in this license in the
 * documentation and/or other materials provided with the distribution; 3) Any
 * documentation included with all redistributions must include the following
 * acknowledgement: "This product includes software developed by the Community
 * Grids Lab. For further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/." Alternatively, this acknowledgement may
 * appear in the software itself, and wherever such third-party acknowledgments
 * normally appear. 4) The name Indiana University or Community Grids Lab or
 * NaradaBrokering, shall not be used to endorse or promote products derived
 * from this software without prior written permission from Indiana University.
 * For written permission, please contact the Advanced Research and Technology
 * Institute ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202. 5)
 * Products derived from this software may not be called NaradaBrokering, nor
 * may Indiana University or Community Grids Lab or NaradaBrokering appear in
 * their name, without prior written permission of ARTI. Indiana University
 * provides no reassurances that the source code provided does not infringe the
 * patent or any other intellectual property rights of any other entity. Indiana
 * University disclaims any liability to any recipient for claims brought by any
 * other entity based on infringement of intellectual property rights or
 * otherwise. LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
 * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
 * GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 * GENERATED USING SOFTWARE.
 */
/**
 * Software License, Version 1.0 Copyright 2003 The Trustees of Indiana
 * University. All rights reserved. Redistribution and use in source and binary
 * forms, with or without modification, are permitted provided that the
 * following conditions are met: 1) All redistributions of source code must
 * retain the above copyright notice, the list of authors in the original source
 * code, this list of conditions and the disclaimer listed in this license; 2)
 * All redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the disclaimer listed in this license in the
 * documentation and/or other materials provided with the distribution; 3) Any
 * documentation included with all redistributions must include the following
 * acknowledgement: "This product includes software developed by the Community
 * Grids Lab. For further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/." Alternatively, this acknowledgement may
 * appear in the software itself, and wherever such third-party acknowledgments
 * normally appear. 4) The name Indiana University or Community Grids Lab or
 * NaradaBrokering, shall not be used to endorse or promote products derived
 * from this software without prior written permission from Indiana University.
 * For written permission, please contact the Advanced Research and Technology
 * Institute ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202. 5)
 * Products derived from this software may not be called NaradaBrokering, nor
 * may Indiana University or Community Grids Lab or NaradaBrokering appear in
 * their name, without prior written permission of ARTI. Indiana University
 * provides no reassurances that the source code provided does not infringe the
 * patent or any other intellectual property rights of any other entity. Indiana
 * University disclaims any liability to any recipient for claims brought by any
 * other entity based on infringement of intellectual property rights or
 * otherwise. LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
 * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
 * GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 * GENERATED USING SOFTWARE.
 */
package cgl.narada.transport.ssl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import javax.net.ServerSocketFactory;

import org.apache.log4j.Logger;

/**
 * This is SSL server side control program. Its only purpose is to provide peer
 * its certificate. Client of this class can call close() method to close the
 * socket after getting it. Modified by HG.
 * 
 * @author Hongbin Liu
 * @author Harshawardhn Gadgil (hgadgil@grids.ucs.indiana.edu)
 * @version 1.0
 */

public class ControlServer extends Thread {

	final static Logger log = Logger.getLogger(ControlServer.class.getName());

	// public final static int CERT_PORT = 33333;
	private ServerSocket serSock;
	private String trustStoreFile;

	// HG: added this so we can find what port is the control server running on
	private int controlServerPort;

	/**
	 * Benefit: No need to concern if port provided is valid or not Obligation:
	 * Set up server socket; Generate keys and certficate
	 */
	public ControlServer(int port) throws SSLControlException {
		setName("ControlServer");

		try {
			serSock = (ServerSocket) ServerSocketFactory.getDefault()
					.createServerSocket(port);

			controlServerPort = serSock.getLocalPort();
			log.debug("Started on port: " + controlServerPort);
		}
		catch (Throwable t) {
			log.warn(t);
			throw new SSLControlException(t.getMessage());
		}

		trustStoreFile = SSLJSSEControl.getInstance().trustStoreFile();
	}

	/**
	 * @return Returns the controlServerPort.
	 */
	public final int getControlServerPort() {
		// HG: Added, so that we can get the port of this control server. This
		// is a read-only property
		return controlServerPort;
	}

	public void run() {
		while (true) {

			try {
				Socket sock = serSock.accept();

				log.info("client request for certificate connected at port "
						+ sock.getLocalPort());

				new Thread(new CertificateSender(sock)).start();
			}
			catch (IOException e) {
				log.error(e);

			}
		}
	}

	private class CertificateSender implements Runnable {

		private Socket sock;

		public CertificateSender(Socket socket) {
			sock = socket;
		}

		/**
		 * Send certificate to client. Benefit: No need to concern if the
		 * recepient is right client. Assume right Socket is set up. Obligation:
		 * Read certificate from a file and send over to client; Check
		 * certificate file exists in the system (embedded in FileInputStream
		 * constructor).
		 */
		public void run() {

			if (trustStoreFile == null) {
				log.warn("no certificate file to send");
				return;
			}

			File trustStore = new File(trustStoreFile);
			int bufSize = 8192, nread;
			byte[] buf = new byte[bufSize];
			BufferedInputStream bis = null;
			BufferedOutputStream bos = null;

			try {
				bis = new BufferedInputStream(new FileInputStream(trustStore));
				bos = new BufferedOutputStream(sock.getOutputStream());

				while ((nread = bis.read(buf, 0, bufSize)) != -1) {
					bos.write(buf, 0, nread);
					bos.flush();
				}
			}
			catch (Exception e) {
				log.warn("server can't send certificate to client");
				log.error("", e);
			}

			try {
				bis.close();
				bos.close();
				sock.close();
			}
			catch (IOException e) {}
			log.debug("finish sending certificate");
		}
	}

	/**
	 * Close both Socket and ServerSocket
	 */
	public void close() throws SSLControlException {
		try {
			serSock.close();
		}
		catch (Exception e) {
			throw new SSLControlException(e.getMessage());
		}
	}

}
